﻿using Microsoft.TeamFoundation.MVVM;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace DBProject2.ViewModel
{
    internal class DataBaseViewModel : ObservableObject
    {
        //private bool _isCollectionFiltered;

        //public bool isCollectionFiltered
        //{
        //    get { return _isCollectionFiltered; }
        //    set
        //    {
        //        if (_isCollectionFiltered != value)
        //        {
        //            _isCollectionFiltered = value;
        //            RaisePropertyChanged("isCollectionFiltered");
        //        }
        //    }
        //}
        #region [ Members ]

        public ObservableCollection<ContactViewModel> Contacts { get; set; }

        ICollectionView extView;

        public ObservableCollection<ContactViewModel> Graveyard { get; set; }

        #endregion [ Members ]

        #region [ Commands ]

        private ICommand _AddContactCommand;

        public ICommand AddContactCommand
        {
            get
            {
                if (_AddContactCommand == null)
                {
                    _AddContactCommand = new RelayCommand
                                                                                        (
                                                                                                param => _AddEntry(Contacts, "", "", "", "", ""),

                                                                                                param => /*this.Contacts.Count < 5*/ true
                                                                                        );
                }
                return _AddContactCommand;
            }
        }

        private ICommand _SortViewCommand;

        public ICommand SortViewCommand
        {
            get
            {
                if (_SortViewCommand == null)
                {
                    _SortViewCommand = new RelayCommand
                    (
                        param => _Sort((string)param),

                        param => true
                    );
                }
                return _SortViewCommand;
            }
        }

        private ICommand _NewDatabaseCommand;

        public ICommand NewDatabaseCommand
        {
            get
            {
                if (_NewDatabaseCommand == null)
                {
                    _NewDatabaseCommand = new RelayCommand

                    (
                        param => _ClearDataBase("Are you sure you want to proceed? If you do you'll lose all unsaved changes to your current database!"),

                        param => Contacts.Count > 0
                    );
                }
                return _NewDatabaseCommand;
            }
        }

        private ICommand _RemoveContactCommand;

        public ICommand RemoveContactCommand
        {
            get
            {
                if (_RemoveContactCommand == null)
                {
                    _RemoveContactCommand = new RelayCommand
                                    (
                                                param => _Remove(Contacts, param),

                                                param => param != null
                                    );
                }
                return _RemoveContactCommand;
            }
        }

        private ICommand _ReturnContactCommand;

        public ICommand ReturnContactCommand
        {
            get
            {
                if (_ReturnContactCommand == null)
                {
                    _ReturnContactCommand = new RelayCommand
                                                                                    (
                                                                                                                                    param => _Return(Contacts, param),

                                                                                                                                    param => param != null
                                                                                    );
                }
                return _ReturnContactCommand;
            }
        }

        private ICommand _EraseContactCommand;

        public ICommand EraseContactCommand
        {
            get
            {
                if (_EraseContactCommand == null)
                {
                    _EraseContactCommand = new RelayCommand
                                    (
                                                param => Graveyard.Remove((ContactViewModel)param),

                                                param => param != null
                                    );
                }
                return _EraseContactCommand;
            }
        }

        private ICommand _LoadContactsCommand;

        public ICommand LoadContactsCommand
        {
            get
            {
                if (_LoadContactsCommand == null)
                {
                    _LoadContactsCommand = new RelayCommand
                    (
                        param => Load("Are you sure you want to load a database? All unsaved changes will be lost!"),

                        param => true
                    );
                }
                return _LoadContactsCommand;
            }
        }

        private ICommand _SaveContactsCommand;

        public ICommand SaveContactsCommand
        {
            get
            {
                if (_SaveContactsCommand == null)
                {
                    _SaveContactsCommand = new RelayCommand
                    (
                    param => Save("Are you sure you want to save the current Database?"),

                    param => Contacts.Count > 0
                    );
                }
                return _SaveContactsCommand;
            }
        }

        private ICommand _FilterContactsCommand;

        public ICommand FilterContactsCommand
        {
            get
            {
                if (_FilterContactsCommand == null)
                {
                    _FilterContactsCommand = new RelayCommand
                    (
                        param => this.extView.Filter = delegate(object item)
                        {
                            //isCollectionFiltered = (string)param != null;

                            ContactViewModel filteredContact = (ContactViewModel)item;
                            return (filteredContact != null) && (filteredContact.LastName.Contains((string)param) || filteredContact.FirstName.Contains((string)param)
                                || filteredContact.Age.ToString().Contains((string)param) || filteredContact.Email.Contains((string)param)
                                || filteredContact.PhoneNumber.ToString().Contains((string)param));
                        },

                        param => true
                    );
                }
                return _FilterContactsCommand;
            }
        }

        #endregion [ Commands ]

        #region [ Methods ]

        private void Load(string msg)
        {
            if (_YesNoDialog(msg) == true)
            {
                string loadFile = "";
                string binFile = "";

                //Create OpenFileDialog
                Microsoft.Win32.OpenFileDialog loadDialog = new Microsoft.Win32.OpenFileDialog();
                loadDialog.InitialDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
                loadDialog.RestoreDirectory = true;

                //Filter for file extension and default file extension
                loadDialog.DefaultExt = ".dbf";
                loadDialog.Filter = "DataBaseFile (*.dbf)|*.dbf";

                // Display OpenFileDialog
                Nullable<bool> dialogResult = loadDialog.ShowDialog();

                // Get the selected file name and display in a TextBox
                if (dialogResult == true)
                {
                    // Open document
                    loadFile = loadDialog.FileName;
                    binFile = loadFile.Remove(loadFile.Length - 1, 1) + "b";
                }

                // If there was a valid database file specified, load it
                if (File.Exists(loadFile))
                {
                    try
                    {
                        // Clear current database collection
                        this.Contacts.Clear();

                        // Open database file, read it line by line splitting database elements with ";"
                        // and add database entries using acquired values
                        using (StreamReader sReader = new StreamReader(File.OpenRead(loadFile)))
                            while (!sReader.EndOfStream)
                            {
                                string line = sReader.ReadLine();
                                var values = line.Split(';');
                                _AddEntry(Contacts, values[0], values[1], values[2], values[3], values[4]);
                            }

                        //Clear Graveyard collection
                        this.Graveyard.Clear();

                        // Check if there is a bin file. If yes load it to Graveyard collection
                        if (File.Exists(binFile))
                        {
                            using (StreamReader sReader = new StreamReader(File.OpenRead(binFile)))

                                while (!sReader.EndOfStream)
                                {
                                    string line = sReader.ReadLine();
                                    var values = line.Split(';');
                                    _AddEntry(Graveyard, values[0], values[1], values[2], values[3], values[4]);
                                }
                        }
                    }
                    catch (Exception exc)
                    {
                        MessageBox.Show(exc.Message);
                    }
                }
                else
                {
                    MessageBox.Show("File Not Specified");
                }
            }
        }

        private void Save(string msg)
        {
            if (_YesNoDialog(msg) == true)
            {
                string saveFile = "";
                string binFile = "";

                //Create SaveFileDialog
                Microsoft.Win32.SaveFileDialog saveDialog = new Microsoft.Win32.SaveFileDialog();
                saveDialog.InitialDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
                saveDialog.RestoreDirectory = true;

                //Filter for file extension and default file extension
                saveDialog.DefaultExt = ".dbf";
                saveDialog.Filter = "DataBaseFile (*.dbf)|*.dbf";

                //Display SaveFileDialog
                Nullable<bool> dialogResult = saveDialog.ShowDialog();

                //Retrieve the selected file name
                if (dialogResult == true)
                {
                    // Save main Contacts list to saveFile
                    saveFile = saveDialog.FileName;

                    using (StreamWriter sWriter = new StreamWriter(saveFile))
                        foreach (ContactViewModel contact in this.Contacts)
                        {
                            sWriter.WriteLine
                                (
                                    "{0};{1};{2};{3};{4}",
                                    contact.FirstName,
                                    contact.LastName,
                                    contact.Age,
                                    contact.Email,
                                    contact.PhoneNumber
                                );
                        }

                    //Save the Graveyard to binFile (same as saveFile but with .dbb instead of .dbf)
                    binFile = saveFile.Remove(saveFile.Length - 1, 1) + "b";

                    using (StreamWriter sWriter = new StreamWriter(binFile))
                        foreach (ContactViewModel contact in this.Graveyard)
                        {
                            sWriter.WriteLine
                                (
                                    "{0};{1};{2};{3};{4}",
                                    contact.FirstName,
                                    contact.LastName,
                                    contact.Age,
                                    contact.Email,
                                    contact.PhoneNumber
                                );
                        }
                }
            }
        }

        private void _AddEntry(ObservableCollection<ContactViewModel> col, string fName, string lName, string age, string eMail, string pNum)
        {
            col.Add
                (
                    new ContactViewModel
                    {
                        FirstName = fName,
                        LastName = lName,
                        Age = ((age != "") ? byte.Parse(age) : (Nullable<byte>)null),
                        Email = eMail,
                        PhoneNumber = ((pNum != "") ? UInt32.Parse(pNum) : (Nullable<UInt32>)null)
                    }
                );
        }

        private void _Remove(ObservableCollection<ContactViewModel> col, object obj)
        {
            ContactViewModel temp = (ContactViewModel)obj;
            if (temp.LastName != "" || temp.FirstName != "" || temp.Age != null || temp.Email != "" || temp.PhoneNumber != null)
            {
                Graveyard.Add((ContactViewModel)obj);
            }
            col.Remove((ContactViewModel)obj);
        }

        private void _Sort(string param)
        {
            extView.SortDescriptions.Clear();

            //return MessageBox.Show((new NotImplementedException()).Message);

            switch (param)
            {
                case "SortByLastNameDesc":
                    extView.SortDescriptions.Add(new SortDescription("LastName", ListSortDirection.Descending));
                    break;
                case "SortByLastNameAsc":
                    extView.SortDescriptions.Add(new SortDescription("LastName", ListSortDirection.Ascending));
                    break;
                case "SortByFirstNameDesc":
                    extView.SortDescriptions.Add(new SortDescription("FirstName", ListSortDirection.Descending));
                    break;
                case "SortByFirstNameAsc":
                    extView.SortDescriptions.Add(new SortDescription("FirstName", ListSortDirection.Ascending));
                    break;
                case "SortByAgeDesc":
                    extView.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Descending));
                    break;
                case "SortByAgeAsc":
                    extView.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Ascending));
                    break;
                default:
                    return;
            }
        }

        private void _Return(ObservableCollection<ContactViewModel> col, object obj)
        {
            col.Add((ContactViewModel)obj);
            Graveyard.Remove((ContactViewModel)obj);
        }

        private void _ClearDataBase(string msg)
        {
            if (_YesNoDialog(msg) == true)
            {
                this.Contacts.Clear();
                this.Graveyard.Clear();
            }
        }

        private bool _YesNoDialog(string msg)
        {
            string caption = "Warning";

            var result = MessageBox.Show(msg,
                                         caption,
                                         MessageBoxButton.YesNo,
                                         MessageBoxImage.Question);

            if (result == MessageBoxResult.Yes)
                return true;
            else return false;
        }

        #endregion [ Methods ]

        #region [ Construction ]

        /// <summary>
        /// Constructs the default instance of a DatabaseViewModel
        /// </summary>
        public DataBaseViewModel()
        {
            Contacts = new ObservableCollection<ContactViewModel>();
            extView = CollectionViewSource.GetDefaultView(Contacts);
            Graveyard = new ObservableCollection<ContactViewModel>();
            //isCollectionFiltered = false;
        }

        #endregion [ Construction ]
    }
}